package com.aluka.nirvana.framework.security.configuration;

import cn.hutool.core.util.ArrayUtil;
import com.aluka.nirvana.framework.security.handler.*;
import com.aluka.nirvana.framework.security.provider.AuthenticationValidProvider;
import com.aluka.nirvana.framework.security.provider.DefaultAuthenticationProvider;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.List;

/**
 * 权限配置
 * @author gongli
 * @since 2019/4/10 13:40
 */
@Configuration
@EnableWebSecurity
@EnableConfigurationProperties(SecurityCustomsConfiguration.class)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{

    @Autowired
    private SecurityCustomsConfiguration customsConfiguration;
    /**
     * 自定义登陆成功处理器
     * */
    @Autowired
    private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

    /**
     * 自定义登陆失败处理器
     * */
    @Autowired
    private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    /**
     * 自定义注销成功处理器
     * */
    @Autowired
    private CustomLogoutSuccessHandler customLogoutSuccessHandler;

    /**
     * 自定义暂无权限处理器
     * */
    @Autowired
    private CustomAuthAccessDeniedHandler customAuthAccessDeniedHandler;

    /**
     * 自定义未登录的处理器
     * */
    @Autowired
    private CustomAuthenticationEntryPointHandler customAuthenticationEntryPointHandler;

    /**
     * 权限验证拦截
     * */
    @Autowired(required = false)
    private AuthenticationValidProvider authenticationValidProvider;

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    @ConditionalOnMissingBean(AuthenticationProvider.class)
    public AuthenticationProvider defaultAuthenticationProvider(){
        return new DefaultAuthenticationProvider();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //这里可启用我们自己的登陆验证逻辑
        auth.authenticationProvider(getApplicationContext().getBean(AuthenticationProvider.class));
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        List<String> openResources = Lists.newArrayList(customsConfiguration.getOpenResources().split(","));

        http.authorizeRequests()
                //不进行权限验证的请求或资源(从配置文件中读取)
                .antMatchers(ArrayUtil.toArray(openResources, String.class)).permitAll()
                //其他的需要登陆后才能访问
                .anyRequest().authenticated()
                .and()
                //配置未登录自定义处理类
                .httpBasic().authenticationEntryPoint(customAuthenticationEntryPointHandler)
                .and()
                //配置登录地址
                .formLogin()
                .loginProcessingUrl(customsConfiguration.getLoginUrl())
                //配置登录成功自定义处理类
                .successHandler(customAuthenticationSuccessHandler)
                //配置登录失败自定义处理类
                .failureHandler(customAuthenticationFailureHandler)
                .and()
                //配置登出地址
                .logout()
                .logoutUrl(customsConfiguration.getLogoutUrl())
                //配置用户登出自定义处理类
                .logoutSuccessHandler(customLogoutSuccessHandler)
                .and()
                //配置没有权限自定义处理类
                .exceptionHandling().accessDeniedHandler(customAuthAccessDeniedHandler)
                .and()
                // 取消跨站请求伪造防护
                .csrf().disable();
        // 基于Token不需要session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        // 禁用缓存
        http.headers().cacheControl();
        // 添加JWT过滤器
        openResources.add(customsConfiguration.getLoginUrl());
        openResources.add(customsConfiguration.getLogoutUrl());

        CustomTokenAuthenticationHandler authenticationHandler = new CustomTokenAuthenticationHandler(authenticationManager());
        authenticationHandler.setOpenResources(ArrayUtil.toArray(openResources, String.class));
        authenticationHandler.setAuthenticationValidProvider(authenticationValidProvider);
        authenticationHandler.setAuthenticationValidEnabled(customsConfiguration.isAuthenticationValidEnabled());
        http.addFilter(authenticationHandler);
    }


}
